package com.gnerv.battle.boot.module.base.interceptor.mybatis;

import com.gnerv.battle.boot.common.base.exception.BusinessException;
import com.gnerv.battle.boot.common.spring.tool.SpringContextTools;
import com.gnerv.battle.boot.module.base.service.TenantService;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.update.Update;
import org.springframework.context.ApplicationContext;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Set;

/**
 * @author Gnerv LiGen
 */
public class BattleTenantSqlParserHandler {

    public static final String CREATOR = "creator ";

    public TenantService tenantService;

    public String handle(String sql) {
        ApplicationContext applicationContext = SpringContextTools.getApplicationContext();
        this.tenantService = applicationContext.getBean(TenantService.class);
        Set<String> accountUkIdSet = tenantService.listAccountUkIdByRoleAndOrg();
        if(CollectionUtils.isEmpty(accountUkIdSet)){
            throw new BusinessException("permission error");
        }
        List<StringValue> accountUkIdList = accountUkIdSet.stream().map(StringValue::new).toList();
        ExpressionList<StringValue> itemsList = new ExpressionList<>(accountUkIdList);
        Parenthesis parenthesis = new Parenthesis(itemsList);
        Statement parse = null;
        try {
            parse = CCJSqlParserUtil.parse(sql);
        } catch (JSQLParserException e) {
            throw new RuntimeException(e);
        }
        if (parse instanceof PlainSelect plainSelect) {
            return plainSelect(plainSelect, parenthesis);
        }
        if (parse instanceof Delete delete) {
            return delete(delete, parenthesis);
        }
        if (parse instanceof Update update) {
            return update(update, parenthesis);
        }
        if (parse instanceof Insert insert) {
            return insert(insert, parenthesis);
        }
        return null;
    }

    public String plainSelect(PlainSelect plainSelect, Parenthesis parenthesis) {
        Table table = (Table) plainSelect.getFromItem();
        InExpression inExpression = createInExpression(table, parenthesis);
        Expression where = plainSelect.getWhere();
        Expression expression = createExpression(where, inExpression);
        plainSelect.setWhere(expression);
        return plainSelect.toString();
    }

    public String delete(Delete delete, Parenthesis parenthesis) {
        InExpression inExpression = createInExpression(delete.getTable(), parenthesis);
        Expression where = delete.getWhere();
        Expression expression = createExpression(where, inExpression);
        delete.setWhere(expression);
        return delete.toString();
    }

    public String update(Update update, Parenthesis parenthesis) {
        InExpression inExpression = createInExpression(update.getTable(), parenthesis);
        Expression where = update.getWhere();
        Expression expression = createExpression(where, inExpression);
        update.setWhere(expression);
        return update.toString();
    }

    public String insert(Insert insert, Parenthesis parenthesis) {
        return insert.toString();
    }

    public InExpression createInExpression(Table table, Parenthesis parenthesis) {
        String createBy = CREATOR;
        if (table.getAlias() != null) {
            createBy = table.getAlias().getName() + "." + createBy;
        }else {
            createBy = table.getName() + "." + createBy;
        }
        return new InExpression(new Column(createBy), parenthesis);
    }

    public Expression createExpression(Expression where, InExpression inExpression) {
        if (where != null) {
            // AND 表达式
            AndExpression andExpression = new AndExpression();
            // AND 左边表达式
            andExpression.setLeftExpression(where);
            // AND 右边表达式
            andExpression.setRightExpression(inExpression);
            return andExpression;
        } else {
            return inExpression;
        }
    }

}
